package org.jeecg.modules.code.ry.util;

import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*;

import javax.sql.DataSource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @description: 事务管理切面
 * @author: lc
 * @create: 2019-10-24 15:24
 **/
@Aspect
@Configuration
public class TransactionManagerConfiguration {
    @Autowired
    private DataSource dataSource;

    /**
     * 切点（只切有service注解的）
     */
    private static final String AOP_POINTCUT_EXPRESSION = "(@within(org.springframework.stereotype.Service))";
    /**
     * 默认的需要事务的操作
     */
    private static final String[] DEFAULT_TRANSACTION_ATTRIBUTES = {"add*", "save*", "insert*", "delete*", "update*", "edit*", "batch*", "create*", "remove*"};
    /**
     * 只读操作
     */
    private static final String[] DEFAULT_READ_ONLY_TRANSACTION_ATTRIBUTES = {"get*", "count*", "find*", "query*", "select*", "list*", "page*","exec*","*",};

    @Bean
    public TransactionInterceptor txAdvice(@Autowired PlatformTransactionManager transactionManager) {
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        RuleBasedTransactionAttribute readOnlyTx = this.readOnlyBasedTransactionAttribute();
        RuleBasedTransactionAttribute requiredTx = this.transactionRuleBasedTransactionAttribute();
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        for (String readOnly :
                DEFAULT_READ_ONLY_TRANSACTION_ATTRIBUTES) {
            txMap.put(readOnly, readOnlyTx);
        }
        for (String transaction :
                DEFAULT_TRANSACTION_ATTRIBUTES) {
            txMap.put(transaction, requiredTx);
        }
        source.setNameMap(txMap);
        TransactionInterceptor transactionInterceptor = new TransactionInterceptor(transactionManager,source);
        transactionInterceptor.setTransactionManager(transactionManager);
        Properties transactionAttributes = new Properties();
        transactionAttributes.setProperty("*", "PROPAGATION_REQUIRED,-Throwable");
        transactionInterceptor.setTransactionAttributes(transactionAttributes);
        return transactionInterceptor;
    }

    @Bean
    public Advisor txAdviceAdvisor(TransactionInterceptor txAdvice) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice);
    }


    /**
     * @Description: 获取只读操作
     * @Param:
     * @return:
     * @Author: lc
     * @Date: 2019/10/24 0024 16:19
     */
    private RuleBasedTransactionAttribute readOnlyBasedTransactionAttribute(){
        /*只读事务，不做更新操作*/
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
        return readOnlyTx;
    }

    /**
     * @Description: 获取事务操作
     * @Param:
     * @return:
     * @Author: lc
     * @Date: 2019/10/24 0024 16:19
     */
    private RuleBasedTransactionAttribute transactionRuleBasedTransactionAttribute (){
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
        requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        return requiredTx;
    }
}
